package org.metasketch.editor.toolbox.advanced;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.metasketch.model.BaseModel;
import org.metasketch.model.CommonIdentified;
import org.metasketch.model.IModelChangeListener;
import org.metasketch.model.ModelChangeManager;
import org.metasketch.reflection.RefUtil;
import org.metasketch.reflection.ReflectionAnalyser;

import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;

public class CustomTreeItem extends TreeItem<String> implements
		IModelChangeListener {

	String script;

	BaseModel model;

	CommonIdentified semantic;

	private ModelChangeManager modelChangeManager;

	private boolean showChildren;

	private ModelViewerScripts modelViewerScripts;

	static RefUtil util = new RefUtil();

	// static Groovy

	public CustomTreeItem() {

	}

	public CustomTreeItem(String name) {
		setValue(name);
	}

	public CustomTreeItem(BaseModel model, CommonIdentified semantic,
			ModelChangeManager modelChangeManager,
			ModelViewerScripts modelViewerScripts, boolean showChildren) {
		this.model = model;
		this.semantic = semantic;
		this.modelViewerScripts = modelViewerScripts;
		this.modelChangeManager = modelChangeManager;
		this.showChildren = showChildren;
		modelChangeManager.registerListener(semantic, this);

		try {
			script = modelViewerScripts.getLabels().get(semantic);
			if (script == null)
				script = modelViewerScripts.getLabels().getInherited(semantic);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		refresh();

	}

	private void refresh() {
		try {

			clearAll();

			Class type = semantic.getClass();

			if (script != null) {

				Binding binding = new Binding();
				binding.setVariable("semantic", semantic);
				GroovyShell shell = new GroovyShell(binding);

				Object value = shell.evaluate(script);

				setValue(value.toString());

			} else {

				String className = type.getSimpleName();
				List<String> fields;

				fields = ReflectionAnalyser.getBasicFieldNames(type);

				if (fields.contains("name")) {
					setValue(className + " - "
							+ util.getValue(semantic, "name") + " - "
							+ semantic.getId());
				} else
					setValue(semantic.getClass().getSimpleName() + " - "
							+ semantic.getId());
			}

			if (!showChildren)
				return;

			// go through the collections
			List<String> collections = ReflectionAnalyser
					.getNonNativeCollections(type);
			for (String collectionName : collections) {
				CustomTreeItem collectionRoot = new CustomTreeItem(
						collectionName);
				getChildren().add(collectionRoot);
				Collection list = (Collection) util.getValue(semantic,
						collectionName);
				List<CustomTreeItem> children = new ArrayList<CustomTreeItem>();
				// if (list != null)
				for (Object child : list) {
					CustomTreeItem item = new CustomTreeItem(model,
							(CommonIdentified) child, modelChangeManager,
							modelViewerScripts, false);
					children.add(item);
				}
				collectionRoot.getChildren().addAll(children);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void clearAll() {

		// if (modelChangeManager != null)
		// modelChangeManager.unregisterListener(this);

		ObservableList<TreeItem<String>> items = getChildren();
		for (TreeItem<String> treeItem : items) {

			CustomTreeItem customItem = (CustomTreeItem) treeItem;

			// modelChangeManager.unregisterListener(customItem);
			customItem.clearAll();

		}
		getChildren().clear();
	}

	@Override
	public void removedMainNode(CommonIdentified semantic) {
		if (semantic == this.semantic) {
			getParent().getChildren().remove(this);
			if (modelChangeManager != null)
				modelChangeManager.unregisterListener(this);
		}

	}

	@Override
	public void modelChanged(CommonIdentified semantic) {

		// if its still there, just refresh
		// if (model.getIndex().getById(semantic.getId()) != null) {
		refresh();
		// } else {
		// // if it's no longer there, just remove from parent
		//
		// }

	}

	@Override
	public void relatedModelChanges() {
		// refresh();

	}

	@Override
	public void addedMainNode(CommonIdentified semantic) {
		// TODO Auto-generated method stub

	}

	public CommonIdentified getSemantic() {
		return semantic;
	}

}
